﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Configuration;
using System.Web;
using System.Reflection;
using System.IO;

namespace Ajaxna
{
    /// <summary>
    /// This Http Handler processes all http requests for resources from this or other loaded libraries.
    /// </summary>
    public class Resources : IHttpHandler
    {
        #region IHttpHandler Members

        public bool IsReusable
        {
            get { return true; }
        }

        /// <summary>
        /// This method uses url parameters of "path" and "assembly" to locate the resource and then
        /// writes that resource to the output stream of the current context (web out).
        /// </summary>
        /// <param name="context"></param>
        public void ProcessRequest(HttpContext context)
        {

            // Transpose the query string into a resource name            
            string sQuery = context.Request["path"];
            string assemblyName = context.Request["assembly"];
            
            Assembly assembly = string.IsNullOrEmpty(assemblyName) ? this.GetType().Assembly : Assembly.Load(assemblyName);   
            string resourceName = TransformPathToResourceName(assembly, sQuery);

            // Just blat the resource (string or binary) to the response output stream
            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
            {
                if (stream == null)
                    throw new ArgumentException("Unable to locate resource: " + resourceName);

                //TODO: Consider setting the output file type mime header correctly (defaults to html/text even for images).
                byte[] buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);
                context.Response.OutputStream.Write(buffer, 0, buffer.Length);
            }
        }

        public static string TransformPathToResourceName(Assembly assembly, string path)
        {
            path = path.TrimEnd(new char[] { '?' }); // GET Requests cause this?
            path = path.Replace("/", ".");
            if (path.StartsWith(".")) // the path can start with an invalid period if no path is entered (in an extern assembly).
                path = path.Remove(0, 1); // So just remove it
            
            string resourceName = string.Format("{0}.{1}", assembly.GetName().Name, path);            

            // match against resources in the assembly, using case insensitivity.
            string returnName = resourceName;
            foreach (string name in assembly.GetManifestResourceNames())
            {
                if (name.ToLower() == resourceName.ToLower())
                {
                    returnName = name;
                    break;
                }
            }

            return returnName;
        }

        public static string ReadResourceString(Assembly assembly, string resourceName)
        {
            string ret = "";            
            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
            {
                using (StreamReader sr = new StreamReader(stream))
                {
                    ret = sr.ReadToEnd();
                }
            }
            return ret;
        }
        #endregion
    }      
}
